﻿using System;
using System.Windows.Forms;
using Microsoft.WindowsAPICodePack.Dialogs;

namespace Krile.Kernel.WindowsEx
{
    /// <summary>
    /// Extra message box
    /// </summary>
    /// <remarks>
    /// If the operating system is Vista or later, use more user-friendly dialog.
    /// If operating system is not support it, use original message dialog.
    /// </remarks>
    public static class MessageBoxEx
    {
        /// <summary>
        /// Converting MessageBoxExButtons to MessageBoxButtons
        /// </summary>
        private static MessageBoxButtons ConvertToOriginal(this MessageBoxEx.MessageBoxExButtons value)
        {
            switch (value)
            {
                case MessageBoxEx.MessageBoxExButtons.RetryCancel:
                    return MessageBoxButtons.RetryCancel;
                case MessageBoxEx.MessageBoxExButtons.YesNo:
                    return MessageBoxButtons.YesNo;
                case MessageBoxEx.MessageBoxExButtons.YesNoCancel:
                    return MessageBoxButtons.YesNoCancel;
                case MessageBoxExButtons.OKCancel:
                    return MessageBoxButtons.OKCancel;
                default:
                    return MessageBoxButtons.OK;
            }
        }

        /// <summary>
        /// Converting MessageBoxExButtons to TaskDialogStandardButtons
        /// </summary>
        private static TaskDialogStandardButtons ConvertToNew(this MessageBoxEx.MessageBoxExButtons value)
        {
            switch (value)
            {
                case MessageBoxEx.MessageBoxExButtons.Close:
                    return TaskDialogStandardButtons.Close;
                case MessageBoxEx.MessageBoxExButtons.OK:
                    return TaskDialogStandardButtons.Ok;
                case MessageBoxEx.MessageBoxExButtons.OKCancel:
                    return TaskDialogStandardButtons.Ok | TaskDialogStandardButtons.Cancel;
                case MessageBoxEx.MessageBoxExButtons.RetryCancel:
                    return TaskDialogStandardButtons.Retry | TaskDialogStandardButtons.Cancel;
                case MessageBoxEx.MessageBoxExButtons.YesNo:
                    return TaskDialogStandardButtons.Yes | TaskDialogStandardButtons.No;
                case MessageBoxEx.MessageBoxExButtons.YesNoCancel:
                    return TaskDialogStandardButtons.Yes | TaskDialogStandardButtons.No | TaskDialogStandardButtons.Cancel;
                default:
                    return TaskDialogStandardButtons.Close;
            }
        }

        /// <summary>
        /// Converting MessageBoxExIcon to MessageBoxIcon
        /// </summary>
        private static MessageBoxIcon ConvertToOriginal(this MessageBoxEx.MessageBoxExIcon value)
        {
            switch (value)
            {
                case MessageBoxEx.MessageBoxExIcon.Error:
                    return MessageBoxIcon.Error;
                case MessageBoxEx.MessageBoxExIcon.Information:
                    return MessageBoxIcon.Information;
                case MessageBoxEx.MessageBoxExIcon.Question:
                    return MessageBoxIcon.Question;
                case MessageBoxEx.MessageBoxExIcon.Shield:
                case MessageBoxEx.MessageBoxExIcon.Warning:
                    return MessageBoxIcon.Warning;
                default:
                    return MessageBoxIcon.None;
            }
        }

        /// <summary>
        /// Converting MessageBoxExIcon to TaskDialogStandardIcon
        /// </summary>
        private static TaskDialogStandardIcon ConvertToNew(this MessageBoxEx.MessageBoxExIcon value)
        {
            switch (value)
            {
                case MessageBoxEx.MessageBoxExIcon.Error:
                    return TaskDialogStandardIcon.Error;
                case MessageBoxEx.MessageBoxExIcon.Information:
                case MessageBoxEx.MessageBoxExIcon.Question:
                    return TaskDialogStandardIcon.Information;
                case MessageBoxEx.MessageBoxExIcon.Shield:
                    return TaskDialogStandardIcon.Shield;
                case MessageBoxEx.MessageBoxExIcon.Warning:
                    return TaskDialogStandardIcon.Warning;
                default:
                    return TaskDialogStandardIcon.None;
            }
        }

        /// <summary>
        /// Converting DialogResult to DialogResultEx
        /// </summary>
        private static MessageBoxEx.DialogResultEx ConvertToEx(this DialogResult value)
        {
            switch (value)
            {
                case DialogResult.Abort:
                case DialogResult.Cancel:
                    return MessageBoxEx.DialogResultEx.Cancel;
                case DialogResult.No:
                    return MessageBoxEx.DialogResultEx.No;
                case DialogResult.OK:
                    return MessageBoxEx.DialogResultEx.OK;
                case DialogResult.Retry:
                    return MessageBoxEx.DialogResultEx.Retry;
                case DialogResult.Yes:
                    return MessageBoxEx.DialogResultEx.Yes;
                default:
                    return MessageBoxEx.DialogResultEx.Close;
            }
        }

        /// <summary>
        /// Converting TaskDialogResult to DialogResultEx
        /// </summary>
        private static MessageBoxEx.DialogResultEx ConvertToEx(this TaskDialogResult value)
        {
            switch (value)
            {
                case TaskDialogResult.Cancel:
                    return MessageBoxEx.DialogResultEx.Cancel;
                case TaskDialogResult.Close:
                case TaskDialogResult.CustomButtonClicked:
                    return MessageBoxEx.DialogResultEx.Close;
                case TaskDialogResult.No:
                    return MessageBoxEx.DialogResultEx.No;
                case TaskDialogResult.Ok:
                    return MessageBoxEx.DialogResultEx.OK;
                case TaskDialogResult.Retry:
                    return MessageBoxEx.DialogResultEx.Retry;
                case TaskDialogResult.Yes:
                    return MessageBoxEx.DialogResultEx.Yes;
                default:
                    return MessageBoxEx.DialogResultEx.Close;
            }
        }

        public enum MessageBoxExButtons { OK, OKCancel, RetryCancel, YesNo, YesNoCancel, Close };

        public enum MessageBoxExIcon { None, Error, Warning, Information, Question, Shield };

        public enum DialogResultEx { OK = 1, Cancel = -1, Retry = 0, Yes = 1, No = 0, Close = 0 };

        public static bool TaskDialogSupported
        {
            get
            {
                return Environment.OSVersion.Version.Major >= 6;
            }
        }

        public static DialogResultEx Show(string text)
        {
            return ShowDialog((IWin32Window)null, text);
        }

        public static DialogResultEx ShowDialog(IWin32Window owner, string text)
        {
            return ShowDialog(owner, text, null);
        }

        public static DialogResultEx Show(string text, string caption)
        {
            return ShowDialog((IWin32Window)null, text, null, caption);
        }

        public static DialogResultEx ShowDialog(IWin32Window owner, string text, string caption)
        {
            return ShowDialog(owner, text, null, caption);
        }

        public static DialogResultEx Show(string instruction, string text, string caption)
        {
            return ShowDialog((IWin32Window)null, instruction, text, caption);
        }

        public static DialogResultEx ShowDialog(IWin32Window owner, string instruction, string text, string caption)
        {
            if (TaskDialogSupported)
            {
                try
                {
                    using (var td = new TaskDialog())
                    {
                        td.InstructionText = instruction;
                        td.Caption = caption;
                        td.Text = text;
                        td.StandardButtons = TaskDialogStandardButtons.Close;
                        if (owner != null)
                            td.OwnerWindowHandle = owner.Handle;
                        return td.Show().ConvertToEx();
                    }
                }
                catch (NotSupportedException e)
                {
                    if (Bridge.DebugReporter != null)
                        Bridge.DebugReporter.AddReport(e);
                }
            }
            if (String.IsNullOrEmpty(instruction))
                return MessageBox.Show(owner, text, caption).ConvertToEx();
            else
                return MessageBox.Show(owner, instruction + Environment.NewLine + text, caption).ConvertToEx();
        }

        public static DialogResultEx Show(string text, string caption, MessageBoxExButtons buttons)
        {
            return ShowDialog((IWin32Window)null, text, caption, buttons);
        }

        public static DialogResultEx ShowDialog(IWin32Window owner, string text, string caption, MessageBoxExButtons buttons)
        {
            if (TaskDialogSupported)
            {
                try
                {
                    using (var td = new TaskDialog())
                    {
                        td.InstructionText = text;
                        td.Caption = caption;
                        td.Text = String.Empty;
                        td.StandardButtons = buttons.ConvertToNew();
                        if (owner != null)
                            td.OwnerWindowHandle = owner.Handle;
                        return td.Show().ConvertToEx();
                    }
                }
                catch (NotSupportedException e)
                {
                    if (Bridge.DebugReporter != null)
                        Bridge.DebugReporter.AddReport(e);
                }
            }
            return MessageBox.Show(owner, text, caption, buttons.ConvertToOriginal()).ConvertToEx();
        }

        public static DialogResultEx Show(string instruction, string text, string caption, MessageBoxExButtons buttons)
        {
            return ShowDialog((IWin32Window)null, instruction, text, caption, buttons);
        }

        public static DialogResultEx ShowDialog(IWin32Window owner, string instruction, string text, string caption, MessageBoxExButtons buttons)
        {
            if (TaskDialogSupported)
            {
                try
                {
                    using (var td = new TaskDialog())
                    {
                        td.InstructionText = instruction;
                        td.Caption = caption;
                        td.Text = text;
                        td.StandardButtons = buttons.ConvertToNew();
                        if (owner != null)
                            td.OwnerWindowHandle = owner.Handle;
                        return td.Show().ConvertToEx();
                    }
                }
                catch (NotSupportedException e)
                {
                    if (Bridge.DebugReporter != null)
                        Bridge.DebugReporter.AddReport(e);
                }
            }
            if (String.IsNullOrEmpty(instruction))
                return MessageBox.Show(owner, text, caption, buttons.ConvertToOriginal()).ConvertToEx();
            else if (String.IsNullOrEmpty(text))
                return MessageBox.Show(owner, instruction, caption, buttons.ConvertToOriginal()).ConvertToEx();
            else
                return MessageBox.Show(owner, instruction + ":" + Environment.NewLine + text, caption, buttons.ConvertToOriginal()).ConvertToEx();
        }

        public static DialogResultEx Show(string text, string caption, MessageBoxExButtons buttons, MessageBoxExIcon icon)
        {
            return ShowDialog((IWin32Window)null, text, caption, buttons, icon);
        }

        public static DialogResultEx ShowDialog(IWin32Window owner, string text, string caption, MessageBoxExButtons buttons, MessageBoxExIcon icon)
        {
            if (TaskDialogSupported)
            {
                try
                {
                    using (var td = new TaskDialog())
                    {
                        td.InstructionText = text;
                        td.Caption = caption;
                        td.Text = String.Empty;
                        td.StandardButtons = buttons.ConvertToNew();
                        td.Icon = icon.ConvertToNew();
                        if (owner != null)
                            td.OwnerWindowHandle = owner.Handle;
                        return td.Show().ConvertToEx();
                    }
                }
                catch (NotSupportedException e)
                {
                    if (Bridge.DebugReporter != null)
                        Bridge.DebugReporter.AddReport(e);
                }
            }
            return MessageBox.Show(owner, text, caption, buttons.ConvertToOriginal(), icon.ConvertToOriginal()).ConvertToEx();
        }

        public static DialogResultEx Show(string instruction, string text, string caption, MessageBoxExButtons buttons, MessageBoxExIcon icon)
        {
            return ShowDialog((IWin32Window)null, instruction, text, caption, buttons, icon);
        }

        public static DialogResultEx ShowDialog(IWin32Window owner, string instruction, string text, string caption, MessageBoxExButtons buttons, MessageBoxExIcon icon)
        {
            if (TaskDialogSupported)
            {
                try
                {
                    using (var td = new TaskDialog())
                    {
                        td.InstructionText = instruction;
                        td.Caption = caption;
                        td.Text = text;
                        td.StandardButtons = buttons.ConvertToNew();
                        td.Icon = icon.ConvertToNew();
                        if (owner != null)
                            td.OwnerWindowHandle = owner.Handle;
                        return td.Show().ConvertToEx();
                    }
                }
                catch (NotSupportedException e)
                {
                    if (Bridge.DebugReporter != null)
                        Bridge.DebugReporter.AddReport(e);
                }
            }
            if (String.IsNullOrEmpty(instruction))
                return MessageBox.Show(owner, text, caption, buttons.ConvertToOriginal(), icon.ConvertToOriginal()).ConvertToEx();
            else if (String.IsNullOrEmpty(text))
                return MessageBox.Show(owner, instruction, caption, buttons.ConvertToOriginal(), icon.ConvertToOriginal()).ConvertToEx();
            else
                return MessageBox.Show(owner, instruction + ":" + Environment.NewLine + text, caption, buttons.ConvertToOriginal(), icon.ConvertToOriginal()).ConvertToEx();
        }

        public static DialogResultEx Show(string text, string caption, out bool noshowagain)
        {
            return ShowDialog((IWin32Window)null, text, null, caption, out noshowagain);
        }

        public static DialogResultEx ShowDialog(IWin32Window owner, string text, string caption, out bool noshowagain)
        {
            return ShowDialog(owner, text, null, caption, out noshowagain);
        }

        public static DialogResultEx Show(string instruction, string text, string caption, out bool noshowagain)
        {
            return ShowDialog((IWin32Window)null, instruction, text, caption, out noshowagain);
        }

        public static DialogResultEx ShowDialog(IWin32Window owner, string instruction, string text, string caption, out bool noshowagain)
        {
            if (TaskDialogSupported)
            {
                try
                {
                    using (var td = new TaskDialog())
                    {
                        td.InstructionText = instruction;
                        td.Caption = caption;
                        td.Text = text;
                        td.StandardButtons = TaskDialogStandardButtons.Close;
                        td.FooterCheckBoxText = Lang.General.NoAskAgain;
                        td.FooterCheckBoxChecked = false;
                        if (owner != null)
                            td.OwnerWindowHandle = owner.Handle;
                        var ret = td.Show().ConvertToEx();
                        if (td.FooterCheckBoxChecked != null)
                            noshowagain = td.FooterCheckBoxChecked.Value;
                        else
                            noshowagain = false;
                        return ret;
                    }
                }
                catch (NotSupportedException e)
                {
                    if (Bridge.DebugReporter != null)
                        Bridge.DebugReporter.AddReport(e);
                }
            }
            noshowagain = false;
            if (String.IsNullOrEmpty(instruction))
                return MessageBox.Show(owner, text, caption).ConvertToEx();
            else
                return MessageBox.Show(owner, instruction + Environment.NewLine + text, caption).ConvertToEx();
        }

        public static DialogResultEx Show(string text, string caption, MessageBoxExButtons buttons, out bool noshowagain)
        {
            return ShowDialog((IWin32Window)null, text, caption, buttons, out noshowagain);
        }

        public static DialogResultEx ShowDialog(IWin32Window owner, string text, string caption, MessageBoxExButtons buttons, out bool noshowagain)
        {
            if (TaskDialogSupported)
            {
                try
                {
                    using (var td = new TaskDialog())
                    {
                        td.InstructionText = text;
                        td.Caption = caption;
                        td.Text = String.Empty;
                        td.StandardButtons = buttons.ConvertToNew();
                        td.FooterCheckBoxText = Lang.General.NoAskAgain;
                        td.FooterCheckBoxChecked = false;
                        if (owner != null)
                            td.OwnerWindowHandle = owner.Handle;
                        var ret = td.Show().ConvertToEx();
                        if (td.FooterCheckBoxChecked != null)
                            noshowagain = td.FooterCheckBoxChecked.Value;
                        else
                            noshowagain = false;
                        return ret;
                    }
                }
                catch (NotSupportedException e)
                {
                    if (Bridge.DebugReporter != null)
                        Bridge.DebugReporter.AddReport(e);
                }
            }
            noshowagain = false;
            return MessageBox.Show(owner, text, caption, buttons.ConvertToOriginal()).ConvertToEx();
        }

        public static DialogResultEx Show(string instruction, string text, string caption, MessageBoxExButtons buttons, out bool noshowagain)
        {
            return ShowDialog((IWin32Window)null, instruction, text, caption, buttons, out noshowagain);
        }

        public static DialogResultEx ShowDialog(IWin32Window owner, string instruction, string text, string caption, MessageBoxExButtons buttons, out bool noshowagain)
        {
            if (TaskDialogSupported)
            {
                try
                {
                    using (var td = new TaskDialog())
                    {
                        td.InstructionText = instruction;
                        td.Caption = caption;
                        td.Text = text;
                        td.StandardButtons = buttons.ConvertToNew();
                        td.FooterCheckBoxText = Lang.General.NoAskAgain;
                        td.FooterCheckBoxChecked = false;
                        if (owner != null)
                            td.OwnerWindowHandle = owner.Handle;
                        var ret = td.Show().ConvertToEx();
                        if (td.FooterCheckBoxChecked != null)
                            noshowagain = td.FooterCheckBoxChecked.Value;
                        else
                            noshowagain = false;
                        return ret;
                    }
                }
                catch (NotSupportedException e)
                {
                    if (Bridge.DebugReporter != null)
                        Bridge.DebugReporter.AddReport(e);
                }
            }
            noshowagain = false;
            if (String.IsNullOrEmpty(instruction))
                return MessageBox.Show(owner, text, caption, buttons.ConvertToOriginal()).ConvertToEx();
            else if (String.IsNullOrEmpty(text))
                return MessageBox.Show(owner, instruction, caption, buttons.ConvertToOriginal()).ConvertToEx();
            else
                return MessageBox.Show(owner, instruction + ":" + Environment.NewLine + text, caption, buttons.ConvertToOriginal()).ConvertToEx();
        }

        public static DialogResultEx Show(string text, string caption, MessageBoxExButtons buttons, MessageBoxExIcon icon, out bool noshowagain)
        {
            return ShowDialog((IWin32Window)null, text, caption, buttons, icon, out noshowagain);
        }

        public static DialogResultEx ShowDialog(IWin32Window owner, string text, string caption, MessageBoxExButtons buttons, MessageBoxExIcon icon, out bool noshowagain)
        {
            if (TaskDialogSupported)
            {
                try
                {
                    using (var td = new TaskDialog())
                    {
                        td.InstructionText = text;
                        td.Caption = caption;
                        td.Text = String.Empty;
                        td.StandardButtons = buttons.ConvertToNew();
                        td.Icon = icon.ConvertToNew();
                        td.FooterCheckBoxText = Lang.General.NoAskAgain;
                        td.FooterCheckBoxChecked = false;
                        if (owner != null)
                            td.OwnerWindowHandle = owner.Handle;
                        var ret = td.Show().ConvertToEx();
                        if (td.FooterCheckBoxChecked != null)
                            noshowagain = td.FooterCheckBoxChecked.Value;
                        else
                            noshowagain = false;
                        return ret;
                    }
                }
                catch (NotSupportedException e)
                {
                    if (Bridge.DebugReporter != null)
                        Bridge.DebugReporter.AddReport(e);
                }
            }
            noshowagain = false;
            return MessageBox.Show(owner, text, caption, buttons.ConvertToOriginal(), icon.ConvertToOriginal()).ConvertToEx();
        }

        public static DialogResultEx Show(string instruction, string text, string caption, MessageBoxExButtons buttons, MessageBoxExIcon icon, out bool noshowagain)
        {
            return ShowDialog((IWin32Window)null, instruction, text, caption, buttons, icon, out noshowagain);
        }

        public static DialogResultEx ShowDialog(IWin32Window owner, string instruction, string text, string caption, MessageBoxExButtons buttons, MessageBoxExIcon icon, out bool noshowagain)
        {
            if (TaskDialogSupported)
            {
                try
                {
                    using (var td = new TaskDialog())
                    {
                        td.InstructionText = instruction;
                        td.Caption = caption;
                        td.Text = text;
                        td.StandardButtons = buttons.ConvertToNew();
                        td.Icon = icon.ConvertToNew();
                        td.FooterCheckBoxText = Lang.General.NoAskAgain;
                        td.FooterCheckBoxChecked = false;
                        if (owner != null)
                            td.OwnerWindowHandle = owner.Handle;
                        var ret = td.Show().ConvertToEx();
                        if (td.FooterCheckBoxChecked != null)
                            noshowagain = td.FooterCheckBoxChecked.Value;
                        else
                            noshowagain = false;
                        return ret;
                    }
                }
                catch (NotSupportedException e)
                {
                    if (Bridge.DebugReporter != null)
                        Bridge.DebugReporter.AddReport(e);
                }
            }
            noshowagain = false;
            if (String.IsNullOrEmpty(instruction))
                return MessageBox.Show(owner, text, caption, buttons.ConvertToOriginal(), icon.ConvertToOriginal()).ConvertToEx();
            else if (String.IsNullOrEmpty(text))
                return MessageBox.Show(owner, instruction, caption, buttons.ConvertToOriginal(), icon.ConvertToOriginal()).ConvertToEx();
            else
                return MessageBox.Show(owner, instruction + ":" + Environment.NewLine + text, caption, buttons.ConvertToOriginal(), icon.ConvertToOriginal()).ConvertToEx();
        }
    }
}
